<?php


global $BaseTypes;
global $DataTypes;


class BaseTypes {
	
	const    DATA            = "data";
	const    CF              = "cf";
	const    NUMERICO        = "numerico";
	const    UNDEFINED       = "notDefined";
	const    ALFANUMERICO    = "alfanumerico";
	const    PROVINCIA       = "prov";
	const    CODCOM          = "codcom";
	const    CODUFF          = "coduff";	
	
	private static $types = false;
			
	function __construct() {
		
		if(!self::$types) {

		

			self::$types = array (
						
				self::NUMERICO => array(
				 	  -1,
					  function($v, $params = false) {
							$mxl = nvli($params, 'maxlen');
							$mnl = nvli($params, 'minlen', 0); 			
			          		return preg_match("/^[0-9]{".$mnl.",".$mxl."}$/", $v);  
					  }
				),
				
				self::ALFANUMERICO => array(
						-1,
						function($v, $params = false) {
							$mxl = nvli($params, 'maxlen');
							$mnl = nvli($params, 'minlen', 0);
						
							return preg_match("/^[0-9a-zA-Z]{".$mnl.",".$mxl."}$/", $v);
						}
				),
	
				self::CODCOM => array(
						-1,
						function($v) {
						
							return preg_match("/^[A-Z]{1}[0-9]{3}$/", $v);
						}
				),			
				
				
			);
		}	
		
	}
	
	
	public function getParam($type, $name) {

		self::checkType($type);
		
		switch ($name) {
			
			case 'maxlen'		: return self::$types[$type][0]; break;
			case 'validation'	: return self::$types[$type][1]; break;
			
		}
		
		return null;
	}
	
	public function getParams($type) {
		
		self::checkType($type);	
		return self::$types[$type];
	}
	
	public function validate($type, $value, $params) {
		
		self::checkType($type);
		
		$fun = $this->getParam($type, 'validation');
		
		return $fun($value, $params);
		
	}
		
	
	public function checkType($type) {
		if (!isset(self::$types[$type])) {
			throw new TypeException("BaseType: $type", TypeException::UNHANDLED);
		}		
	}
	
}


class DataTypes {
	
	
	const    DATA            = "data";
	const    CF              = "cf";
	const    NUMERICO        = "numerico";
	const    UNDEFINED       = "notDefined";
	const    ALFANUMERICO    = "alfanumerico";
	const    PROVINCIA       = "prov";
	const    CODCOM          = "codcom";
	const    CODUFF          = "coduff";
	
	const	 FOGLIO			 = "foglio";

	
	private static $types = false;
	
	function __construct() {
		
		global $BaseTypes;
	
		if(!self::$types) {
			self::$types = array (
						
				self::NUMERICO		=> array (BaseTypes::NUMERICO, false),
				self::ALFANUMERICO	=> array (BaseTypes::ALFANUMERICO, false),
				self::CODCOM		=> array (BaseTypes::CODCOM, false),				
				self::FOGLIO		=> array (BaseTypes::NUMERICO, array('maxlen' => 5))
				
			);
		}
	
	}	
	
	public function validate($type, $value, $params=false) {
		
		global $BaseTypes;
		self::checkType($type);
	
		if ($this->hasBase($type)) {
			return $BaseTypes->validate(
				self::$types[$type][0],
				$value,
				self::$types[$type][1]
			);
		} else {
			$callable = self::$types[$type][1];
			return $callable($value, $params);
		}
	
	}

	private function checkType($type) {
		if (!isset(self::$types[$type])) {
			throw new TypeException("DataType: $type", TypeException::UNHANDLED);
		}
	}

	private function hasBase($type) {
		return (self::$types[$type][0] !== false);
	}
	
	public function addType($name, $baseType, $paramORfun) {
		if (isset(self::$types[$name])) {
			throw new TypeException($name, TypeException::DEFINED);
		}
		
		if ($baseType === false) {
			if (!is_callable($paramORfun)) {
				throw new TypeException($name, TypeException::DEFINITION, 'not a baseType extension, third param must be a callable');
			}
		} else {
			if(!is_array($paramORfun)) {
				throw new TypeException($name, TypeException::DEFINITION, 'baseType extension, third param must be array of params');
			}
		}
		self::$types[$name][0] = $baseType;
		self::$types[$name][1] = $paramORfun;
		
	}
	
}


$BaseTypes = new BaseTypes;
$DataTypes = new DataTypes;